package axis.dynamic;

import javax.xml.rpc.holders.IntHolder;

import org.apache.axis.Handler;
import org.apache.axis.MessageContext;
import org.apache.axis.constants.Scope;
import org.apache.axis.description.JavaServiceDesc;
import org.apache.axis.handlers.soap.SOAPService;
import org.apache.axis.providers.java.JavaProvider;
import org.apache.axis.providers.java.RPCProvider;

/**
 * Variant of the {@link JavaProvider}s, that does not create the service object but always uses the same instance.
 * 
 * All the methods overridden here are defined in {@link JavaProvider} and are only used in that class.
 * {@link JavaProvider} calls {@link #getServiceObject} and passes the object to {@link RPCProvider#processMessage}.
 */
@SuppressWarnings("serial")  // we don't want to serialize this thing
public class ObjectRPCProvider extends RPCProvider
{
  /** */
  private final Object _target;
  
  /** */
  private final Class<?> _class;
  
  /**
   * uses target.getClass as class.
   * @param target
   */
  public ObjectRPCProvider( Object target )
  {
    this(target, target.getClass());
  }

  /**
   * @param target
   * @param cls class used to find methods etc. 
   */
  public ObjectRPCProvider( Object target, Class<?> cls )
  {
    if (target == null) throw new NullPointerException("target");
    if (cls == null) throw new NullPointerException("class");
    _target = target;
    _class = cls;
  }

  /**
   * @return service class
   */
  private Class<?> getServiceClass()
  {
    return _class;
  }
  
  /**
   * called only from {@link JavaProvider#initServiceDesc}, but we override that, so it's never called.
   * @param clsName
   * @param service
   * @param msgContext
   * @return class set in {@link #ObjectRPCProvider(Object, Class) constructor}.
   * @see JavaProvider#getServiceClass(String, SOAPService, MessageContext)
   */
  @Override
  protected Class<?> getServiceClass( String clsName, SOAPService service, MessageContext msgContext )
  {
    return getServiceClass();
  }
  
  /**
   * called from {@link JavaProvider#invoke}, and from {@link JavaProvider#initServiceDesc} (but we override that here).
   * @param service
   * @return name of class set in {@link #ObjectRPCProvider(Object, Class) constructor}.
   * @see JavaProvider#getServiceClassName(Handler)
   */
  @Override
  protected String getServiceClassName( Handler service )
  {
    return getServiceClass().getName();
  }
  
  /**
   * called from {@link JavaProvider#getServiceClassName} (but we override that here), and from 
   * {@link JavaProvider#invoke} if {@link #getServiceClassName} returns null or "" (and that can't happen).
   * @return null
   * @see JavaProvider#getServiceClassNameOptionName()
   */
  @Override
  protected String getServiceClassNameOptionName()
  {
    return null;
  }
  
  /**
   * called from {@link JavaProvider#invoke} 
   * @param msgContext ignored
   * @param service ignored
   * @param clsName ignored
   * @param scopeHolder we set the scope to {@link Scope#APPLICATION} 
   * @return target object set in {@link #ObjectRPCProvider(Object, Class) constructor}.
   * @see JavaProvider#invoke
   */
  @Override
  public Object getServiceObject( MessageContext msgContext, Handler service, String clsName, IntHolder scopeHolder )
  {
    // tell java provider that there's never any need to destroy this object
    scopeHolder.value = Scope.APPLICATION.getValue();
    return _target;
  }
  
  /** 
   * Called from {@link SOAPService#getInitializedServiceDesc}, which in turn is called from many places.
   * We do not strictly have to override the implementation in JavaProvider, but it's safer this way, because
   * we <b>must</b> make sure that this method can be invoked with a <tt>null</tt> {@link MessageContext}.
   * It is (indirectly) called with a <tt>null</tt> parameter in {@link SoapReceiver#createService}. 
   * The current implementation of {@link JavaProvider#initServiceDesc} only passes on the parameter to 
   * {@link JavaProvider#getServiceClass}, which in our cases ignores it as well. The current implementation of 
   * {@link JavaProvider#getServiceClass} explicitly tolerates a null value.
   * @param service 
   * @param msgContext ignored
   * @see JavaProvider#initServiceDesc
   * @see JavaProvider#getServiceClass
   * @see SoapReceiver#createService
   */ 
  @Override
  public void initServiceDesc( SOAPService service, MessageContext msgContext )
  {
    ((JavaServiceDesc)service.getServiceDescription()).loadServiceDescByIntrospection(_target.getClass());
  }


}

